#include "./BSP/PWMDAC/pwmdac.h"

TIM_HandleTypeDef g_tim9_handler;     /* 定时器9句柄 */
TIM_OC_InitTypeDef g_tim9_ch2handler; /* 定时器9通道2句柄 */

/**
 * @brief      PWM DAC初始化函数, 实际上就是初始化定时器
 * @param[in]  arr         自动重装载值,决定PWM频率
 * @param[in]  psc         时钟预分频数,决定定时器计数频率
 *
 * @note       定时器的时钟来自APB1 / APB2, 当APB1 / APB2 分频时, 定时器频率自动翻倍
 *             所以, 一般情况下, 我们所有定时器的频率, 都是84Mhz 等于系统时钟频率
 *             定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
 *             Ft = 定时器工作频率, 单位: Mhz
 * @retval     无
 */
void pwmdac_init(uint16_t arr, uint16_t psc)
{
    /* 配置定时器基本参数 */
    g_tim9_handler.Instance = PWMDAC_TIMX;                  /* 定时器9 */
    g_tim9_handler.Init.Prescaler = psc;                    /* 设置预分频器 */
    g_tim9_handler.Init.CounterMode = TIM_COUNTERMODE_UP;   /* 向上计数模式 */
    g_tim9_handler.Init.Period = arr;                       /* 自动重装载值 */
    HAL_TIM_PWM_Init(&g_tim9_handler);                      /* 初始化PWM定时器 */

    /* 配置PWM通道参数 */
    g_tim9_ch2handler.OCMode = TIM_OCMODE_PWM1;             /* PWM模式1: CNT<CCR时输出有效电平 */
    g_tim9_ch2handler.Pulse = arr / 2;                      /* 设置比较值,此值用来确定占空比，默认比较值为自动重装载值的一半，即占空比为50% */
    g_tim9_ch2handler.OCPolarity = TIM_OCPOLARITY_HIGH;     /* 输出极性为高电平有效 */
    HAL_TIM_PWM_ConfigChannel(&g_tim9_handler, &g_tim9_ch2handler, PWMDAC_TIMX_CHY);    /* 配置TIM9通道2 */

    HAL_TIM_PWM_Start(&g_tim9_handler, PWMDAC_TIMX_CHY);    /* 启动PWM输出 */
}

/**
 * @brief      定时器PWM底层初始化回调函数
 * @param[in]  htim        定时器句柄指针
 *
 * @note       该函数会被HAL_TIM_PWM_Init()自动调用
 * @retval     无
 */
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    GPIO_InitTypeDef gpio_init_struct;

    if (htim->Instance == PWMDAC_TIMX)
    {
        PWMDAC_TIMX_CLK_ENABLE();           /* 使能TIM9时钟 */
        PWMDAC_GPIO_CLK_ENABLE();           /* 使能GPIOA时钟 */

        /* 配置PWM输出引脚 */
        gpio_init_struct.Pin = PWMDAC_GPIO_PIN;         /* PA3引脚 */
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;        /* 复用推挽输出模式 */
        gpio_init_struct.Pull = GPIO_PULLUP;            /* 上拉 */
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_LOW;   /* 低速 */
        gpio_init_struct.Alternate = PWMDAC_GPIO_AFTIMX;/* 复用为TIM9功能 */
        HAL_GPIO_Init(PWMDAC_GPIO_PORT, &gpio_init_struct);         /* 初始化GPIO */
    }
}

/**
 * @brief      设置PWM DAC输出电压
 *
 * @param[in]  vol         目标电压值,取值范围:0~3300 (对应0~3.3V)
 *
 * @note       该函数通过调节PWM占空比来模拟DAC输出:
 *             - 输入电压范围: 0~3300 (单位:mV)
 *             - 实际电压范围: 0~3.3V
 *             - 分辨率: 取决于定时器的自动重装载值
 *
 *             转换过程:
 *             1. vol/1000 -> 得到实际电压值(V)
 *             2. 电压值 * 256/3.3 -> 转换为PWM比较值
 *             3. 设置CCR寄存器 -> 改变占空比
 *
 *             占空比计算: Duty = (CCR/ARR) * 100%
 *             输出电压: Vout = Vcc * Duty = 3.3V * Duty
 *
 * @retval     无
 */
void pwmdac_set_voltage(uint16_t vol)
{
    float temp = vol;                   /* 转换为浮点数便于计算 */
    temp /= 100;                        /* 缩小100倍,转换为实际电压值(V) */
    temp = temp * 256 / 3.3f;           /* 将电压转换为PWM比较值 */
    __HAL_TIM_SET_COMPARE(&g_tim9_handler, PWMDAC_TIMX_CHY, temp);  /* 设置新的占空比 */
}
